#ifndef __SPECIAL_H__
#define __SPECIAL_H__

#include "common.h"
#include "Token.h"

enum class SpecialCode
{
	UPARROW, STAR, LPAREN,
    DOTDOT, RPAREN, MINUS, PLUS, EQUAL, LBRACKET,
    RBRACKET, COLON, SEMICOLON, LT, GT, COMMA, PERIOD, SLASH,
    COLONEQUAL, LE, GE, NE, AND,
    ARRAY, BEGIN, CASE, CONST, DIV, DO, DOWNTO, ELSE, END, FFILE,
    FOR, FUNCTION, GOTO, IF, IN, LABEL, MOD, NIL, NOT, OF, OR, PACKED,
    PROCEDURE, PROGRAM, RECORD, REPEAT, SET, THEN, TO, TYPE, UNTIL,
    VAR, WHILE, WITH,
};

class SpecialWord
{
private:
	string name;
	SpecialCode code;

	static int max_length;

public:
	SpecialWord(string name, SpecialCode code);

	string getName() const;
	SpecialCode getCode() const;

	static int getMaxLength()
	{
		return max_length;
	}
};

static const SpecialWord sw_table[] = {
    SpecialWord("^",SpecialCode::UPARROW),
	SpecialWord("*",SpecialCode::STAR),
	SpecialWord("(",SpecialCode::LPAREN),
	SpecialWord(")",SpecialCode::RPAREN),
	SpecialWord("-",SpecialCode::MINUS),
	SpecialWord("+",SpecialCode::PLUS),
	SpecialWord("=",SpecialCode::EQUAL),
	SpecialWord("[",SpecialCode::LBRACKET),
	SpecialWord("]",SpecialCode::RBRACKET),
	SpecialWord(":",SpecialCode::COLON),
	SpecialWord(";",SpecialCode::SEMICOLON),
	SpecialWord("<",SpecialCode::LT),
	SpecialWord(">",SpecialCode::GT),
	SpecialWord(",",SpecialCode::COMMA),
	SpecialWord(".",SpecialCode::PERIOD),
	SpecialWord("/",SpecialCode::SLASH),
	SpecialWord(":=",SpecialCode::COLONEQUAL),
	SpecialWord("<=",SpecialCode::LE),
	SpecialWord(">=",SpecialCode::GE),
	SpecialWord("<>",SpecialCode::NE),
	SpecialWord("..",SpecialCode::DOTDOT),
	SpecialWord("do",SpecialCode::DO),
	SpecialWord("if",SpecialCode::IF),
	SpecialWord("in",SpecialCode::IN),
	SpecialWord("of",SpecialCode::OF),
	SpecialWord("or",SpecialCode::OR),
	SpecialWord("to",SpecialCode::TO),
    SpecialWord("and",SpecialCode::AND),
	SpecialWord("div",SpecialCode::DIV),
	SpecialWord("end",SpecialCode::END),
	SpecialWord("for",SpecialCode::FOR),
	SpecialWord("mod",SpecialCode::MOD),
	SpecialWord("nil",SpecialCode::NIL),
	SpecialWord("not",SpecialCode::NOT),
	SpecialWord("set",SpecialCode::SET),
	SpecialWord("var",SpecialCode::VAR),
    SpecialWord("case",SpecialCode::CASE),
	SpecialWord("else",SpecialCode::ELSE),
	SpecialWord("file",SpecialCode::FFILE),
	SpecialWord("goto",SpecialCode::GOTO),
	SpecialWord("then",SpecialCode::THEN),
	SpecialWord("type",SpecialCode::TYPE),
	SpecialWord("with",SpecialCode::WITH),
    SpecialWord("array",SpecialCode::ARRAY),
	SpecialWord("begin",SpecialCode::BEGIN),
	SpecialWord("const",SpecialCode::CONST),
	SpecialWord("label",SpecialCode::LABEL),
	SpecialWord("until",SpecialCode::UNTIL),
	SpecialWord("while",SpecialCode::WHILE),
    SpecialWord("downto",SpecialCode::DOWNTO),
	SpecialWord("packed",SpecialCode::PACKED),
	SpecialWord("record",SpecialCode::RECORD),
	SpecialWord("repeat",SpecialCode::REPEAT),
    SpecialWord("program",SpecialCode::PROGRAM),
    SpecialWord("function",SpecialCode::FUNCTION),
    SpecialWord("procedure",SpecialCode::PROCEDURE),
};

class Special :
	public Token
{
private:
	static TokenExtractor extractor;

	SpecialCode value;

public:
	Special(string token_str);

	string print() const;
	string printType() const;

	static bool isSpecial(string in);

	static TokenExtractor* getExtractor()
	{
		return &extractor;
	}
};

#endif